package com.ruoyi.framework.web.service;

import javax.annotation.Resource;

import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Set;

/**
 * 登录校验方法
 * 
 * @author ruoyi
 */
@Component
public class SysLoginService
{
    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private ISysUserService userService;

    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid)
    {
        //移除图片验证码验证
        /*String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }*/
        // 用户验证
        Authentication authentication = null;
        try
        {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new CustomException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 手机号验证登录
     * @param phonenumber
     * @param code
     * @param uuid
     * @return
     */
    public String phonenumberLogin(String phonenumber, String code, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + phonenumber + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);

        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        LoginUser loginUser = new LoginUser();
        //根据手机号获取用户名
        List<SysUser> sysUser = sysUserService.selectUserByPhonenumber(phonenumber);
        if (CollectionUtils.isEmpty(sysUser))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.mobile.not.exists")));
            throw new UserException("user.mobile.not.exists", null);
        }
        if (sysUser.size()>1)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.mobile.repeat")));
            throw new UserException("user.mobile.repeat", null);
        }
        if (UserStatus.OK.getCode().equals(sysUser.get(0).getStatus())||UserStatus.open.getCode().equals(sysUser.get(0).getStatus())||"1".equals(sysUser.get(0).getForceFlag())){

        }else{
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked")));
            throw new UserException("user.blocked", null);
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        loginUser.setUser(sysUser.get(0));
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(sysUser.get(0));
        loginUser.setPermissions(permissions);

        redisCache.deleteObject(verifyKey);
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     *
     * @param phonenumber 手机号
     * @param password    密码
     * @return
     */
    public int editUserPwd(String phonenumber, String password, String code, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + phonenumber + uuid;
        String captcha = redisCache.getCacheObject(
                verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        if (StringUtils.isNotBlank(phonenumber) && StringUtils.isNotBlank(password)) {
            SysUser user = new SysUser();
            user.setPassword(SecurityUtils.encryptPassword(password));
            user.setPhonenumber(phonenumber);
            List<SysUser> resultUser = sysUserService.selectUserByPhonenumber(phonenumber);
            if(tokenService.getLoginUser(ServletUtils.getRequest())==null) {
                user.setUpdateBy(String.valueOf(resultUser.get(0).getUserId()));
            }else {
                user.setUpdateBy(String.valueOf(tokenService.getLoginUser(ServletUtils.getRequest()).getUser().getUserId()));
            }
            redisCache.deleteObject(verifyKey);
            return sysUserService.resetUserPwdByPhonenumber(user);
        } else {
            return 0;
        }
    }

    /**
     * 验证码校验
     * @param code
     * @param phonenumber
     * @param uuid
     * @return
     */
    public int codeVerify(String code, String phonenumber, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + phonenumber + uuid;
        String captcha = redisCache.getCacheObject(
                verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        redisCache.deleteObject(verifyKey);
        return 1;
    }

    /**
     * 修改手机号码
     * @param newPhonenumber 新手机号码
     * @param code
     * @param uuid
     * @return
     */
    public int updatePhonenumber(String newPhonenumber, String code, String uuid) {
        int i = 0;
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        String oldPhonenumber = loginUser.getUser().getPhonenumber();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + oldPhonenumber + uuid;
        String captcha = redisCache.getCacheObject(
                verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(oldPhonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(oldPhonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        SysUser user = loginUser.getUser();
        user.setPhonenumber(newPhonenumber);
        //新旧手机号码是否一致
        if(oldPhonenumber.equals(newPhonenumber)){
            throw new BaseException("修改手机号失败，新手机号码和原手机号码相同！");
        }
        //先判断手机号是否重复
        boolean res = UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user));
        if(res) {
            throw new BaseException("修改手机号失败，手机号码已存在！");
        }else {
            i = userService.updateUserProfile(user);
            if (i > 0)
            {
                // 更新缓存用户信息
                loginUser.getUser().setPhonenumber(newPhonenumber);
                tokenService.setLoginUser(loginUser);
                redisCache.deleteObject(verifyKey);
                return i;
            }
            throw new BaseException("修改个人信息异常，请联系管理员");
        }
    }
}
